<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */

namespace app\service\report;

use app\enum\ReportRecordEnum;
use app\model\report\ReportRecordExcelModel;
use app\model\report\ReportRecordListModel;
use app\model\StaffFsAccessTokenModel;
use app\model\StaffModel;
use app\service\BaseService;
use app\service\notice\NoticeInterface;
use app\service\notice\NoticeService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

final class ReportRecordSendService extends BaseService
{
    private ?ReportRecordExcelModel $reportModel;

    private ?ReportRecordListModel $reportListModel;

    /**
     * @var mixed webhook
     */
    private array $webhook = [];

    /**
     * @var mixed 客户ids
     */
    private array $staffs = [];

    /**
     * @var int 报表类型
     */
    private int $reportDateType = 0;

    /**
     * @var mixed 报表名称
     */
    private string $reportName = '';

    public function __construct(ReportRecordExcelModel $reportModel, ReportRecordListModel $reportListModel)
    {
        // 报表信息表
        $this->reportModel = $reportModel;
        // 发送报表记录表
        $this->reportListModel = $reportListModel;

        $this->setStaff();
        $this->setWebHook();
        $this->setReportDateType();
        $this->setReportName();
    }

    /**
     * 报表发送.
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function reportSend(): bool
    {
        $this->reportModel = (new ReportRecordExcelModel())->where('is_send', ReportRecordExcelModel::SEND_YES)->find($this->reportListModel->getAttr('report_record_id'));
        if (! $this->reportModel instanceof ReportRecordExcelModel || ! $this->reportModel->getKey()) {
            return self::setError('未知xxx');
        }
        $type = $this->getSendType();
        // email
        if ($type == ReportRecordEnum::REPORT_RECORD_PUSH_MODE_MAILBOX) {
            if ($this->isSendStaff() && ! $this->sendEmail()) {
                return false;
            }

            if ($this->isSendWebHook() && ! $this->sendEmailWebHook()) {
                return false;
            }
        }

        // 钉钉
        if ($type == ReportRecordEnum::REPORT_RECORD_PUSH_MODE_NAIL) {
            if (empty($this->reportListModel->getAttr('success_staff_id'))) {
                if ($this->isSendStaff() && ! $this->sendDingTalk()) {
                    return false;
                }
            }

            if ($this->isSendWebHook() && ! $this->sendDingTalkWebHook()) {
                return false;
            }
        }

        // 飞书
        if ($type == ReportRecordEnum::REPORT_RECORD_PUSH_MODE_FS) {
            if (empty($this->reportListModel->getAttr('success_staff_id'))) {
                if ($this->isSendStaff() && ! $this->sendFs()) {
                    return false;
                }
            }

            if ($this->isSendWebHook() && ! $this->sendFsWebHook()) {
                return false;
            }
        }

        // 企业微信
        if ($type == ReportRecordEnum::REPORT_RECORD_PUSH_MODE_QYWX) {
            if (empty($this->reportListModel->getAttr('success_staff_id'))) {
                if ($this->isSendStaff() && ! $this->sendWeChat()) {
                    return false;
                }
            }

            if ($this->isSendWebHook() && ! $this->sendWeChatWebHook()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 获取发送类型.
     * @return int
     */
    private function getSendType(): int
    {
        return intval($this->reportModel->getAttr('push_mode'));
    }

    /**
     * 设置推送消息接受人.
     */
    private function setStaff()
    {
        // 推送消息接受人
        $this->staffs = ! empty($this->reportModel->getAttr('receive_staff_ids')) ? json_decode($this->reportModel->getAttr('receive_staff_ids'), true) : [];
    }

    /**
     * 获取推送消息接受人.
     * @return array
     */
    private function getStaff(): array
    {
        return $this->staffs ?? [];
    }

    /**
     * 获取报表类型.
     * @return void
     */
    private function setReportDateType()
    {
        $this->reportDateType = intval($this->reportModel->getAttr('report_date_type'));
    }

    /**
     * 获取报表类型.
     * @return int
     */
    private function getReportDateType(): int
    {
        return $this->reportDateType;
    }

    /**
     * 获取报表名称.
     * @return void
     */
    private function setReportName()
    {
        $this->reportName = strval($this->reportModel->getAttr('report_name'));
    }

    /**
     * 获取报表名称.
     * @return string
     */
    private function getReportName(): string
    {
        return strval($this->reportName) ?? '';
    }

    /**
     * 是否需要发送给对应用户.
     * @return bool
     */
    private function isSendStaff(): bool
    {
        return ! empty($this->staffs);
    }

    /**
     * 设置推送webhook.
     */
    private function setWebHook()
    {
        // 推送webhook
        $this->webhook = ! empty($this->reportModel->getAttr('webhook_url')) ? json_decode($this->reportModel->getAttr('webhook_url'), true) : [];
    }

    /**
     * 获取推送webhook.
     * @return array
     */
    private function getWebHook(): array
    {
        return $this->webhook ?? [];
    }

    /**
     * 是否需要发送webhook.
     * @return bool
     */
    private function isSendWebHook(): bool
    {
        return ! empty($this->webhook);
    }

    /**
     * 发送email.
     * @return bool
     */
    private function sendEmail(): bool
    {
        $type = $this->getSendType();
        $receiveStaffIds = $this->getStaff();
        // 邮箱
        $toEmails = (new StaffModel())->whereIn('id', $receiveStaffIds)->column('email');
        $service = NoticeService::getInstance($type);
        if (! $service instanceof NoticeInterface) {
            return self::setError('实例化消息服务错误');
        }
        $sendDate = date('Y-m-d', strtotime(strval($this->reportListModel->getAttr('date'))));
        $subject = 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName();
        $content_body = <<<EOF
                                            				                <html lang="">
                                            				                <body>
                                            				                <p>报表日期：{$sendDate}</p>
                                            				                <p>报表时间：{$this->reportListModel->getAttr('hour')}:00</p>
                                            				                <p>客户自定义报表请见附件</p>
                                            				                </body>
                                            				                </html>
                            EOF;
        $send_result = $service->sendHtmlMail($toEmails, $subject, $content_body, [$this->reportListModel->getAttr('file_url')]);
        // 发送成功记录
        $res = $this->updateStatus($send_result, $receiveStaffIds, $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送email webhook.
     */
    private function sendEmailWebHook(): bool
    {
        // todo email 暂无webhook
        return false;
    }

    /**
     * 发送钉钉.
     * @return bool
     */
    private function sendDingTalk(): bool
    {
        $type = $this->getSendType();
        $receiveStaffIds = $this->getStaff();
        // 钉钉
        $service = NoticeService::getInstance($type);
        if (! $service instanceof NoticeInterface) {
            return self::setError('实例化消息服务错误');
        }
        $cardCode = sprintf(ReportRecordEnum::DING_CARD_TEMPLATE_V3, ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()], $this->getReportName(), $this->reportListModel->getAttr('date'), $this->reportListModel->getAttr('hour'), $this->reportListModel->getAttr('file_url'));
        $successStaffIds = [];
        $rs = [];
        foreach ($receiveStaffIds as $staffId) {
            $userId = $service->getUsersIdByPhone($staffId);
            $res = $service->SendCardMessages(strval($userId), $cardCode);
            if ($res) {
                // 发送成功
                $successStaffIds[] = $staffId;
                $rs[] = $res;
            }
        }
        // 发送成功记录
        $res = $this->updateStatus($rs, $successStaffIds, $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送钉钉 webhook.
     * @return bool
     */
    private function sendDingTalkWebHook(): bool
    {
        $webhook = $this->getWebHook();
        $msg = [];
        $type = ReportRecordEnum::REPORT_RECORD_DING_TALK_WEBHOOK;
        foreach ($webhook as $value) {
            try {
                // 钉钉的webhook
                $hook['link'] = $value;
                $service = NoticeService::getInstance($type, $hook);
                if (! $service instanceof NoticeInterface) {
                    return self::setError('实例化消息服务错误');
                }
                $sendDate = date('Y-m-d', strtotime(strval($this->reportListModel->getAttr('date'))));
                $subject = 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName();
                $data['title'] = $sendDate;
                $data['text'] = $subject;
                $data['messageUrl'] = $this->reportListModel->getAttr('file_url');
                $res = $service->sendSingleMessage($data);
                if ($res) {
                    $msg[] = '成功';
                }
            } catch (\Exception $e) {
                $msg[] = $value;
                continue;
            }
        }
        // 发送成功记录
        $res = $this->updateStatus($msg, [], $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送飞书.
     * @return bool
     */
    private function sendFs(): bool
    {
        $type = $this->getSendType();
        $receiveStaffIds = $this->getStaff();
        // 飞书
        $service = NoticeService::getInstance($type);
        if (! $service instanceof NoticeInterface) {
            return self::setError('实例化消息服务错误');
        }
        $openIds = [];
        $successStaffIds = [];
        foreach ($receiveStaffIds as $staffId) {
            $openId = (new StaffFsAccessTokenModel())->where('staff_id', $staffId)->value('open_id');
            if ($openId) {
                $openIds[] = $openId;
                $successStaffIds[] = $staffId;
            }
        }
        if (empty($openIds)) {
            return self::setError('未知客户');
        }
        $array = [
            'msg_type' => 'interactive',
            'open_ids' => $openIds,
            'card' => [
                'config' => [
                    'wide_screen_mode' => true,
                ],
                'header' => [
                    'template' => 'blue',
                    'title' => [
                        'content' => 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName(),
                        'tag' => 'plain_text',
                    ],
                ],
                'elements' => [
                    [
                        'fields' => [
                            [
                                'is_short' => true,
                                'text' => [
                                    'content' => "**📅 报表日期：**\n" . date('Y-m-d', strtotime(strval($this->reportListModel->getAttr('date')))),
                                    'tag' => 'lark_md',
                                ],
                            ],
                            [
                                'is_short' => true,
                                'text' => [
                                    'content' => "**🕙 报表时间：**\n" . $this->reportListModel->getAttr('hour') . ':00',
                                    'tag' => 'lark_md',
                                ],
                            ],
                        ],
                        'tag' => 'div',
                    ],
                    [
                        'actions' => [
                            [
                                'tag' => 'button',
                                'text' => [
                                    'content' => '🔎 查看报表详情',
                                    'tag' => 'plain_text',
                                ],
                                'type' => 'primary',
                                'url' => $this->reportListModel->getAttr('file_url'),
                            ],
                        ],
                        'tag' => 'action',
                    ],
                ],
            ],
        ];
        $res = $service->sendBatchMessage($array);
        // 发送成功记录
        $res = $this->updateStatus($res, $successStaffIds, $this->reportListModel);

        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送飞书 webhook.
     * @return bool
     */
    private function sendFsWebHook(): bool
    {
        $webhook = $this->getWebHook();
        // 飞书webhook
        $msg = [];
        $type = ReportRecordEnum::REPORT_RECORD_FS_WEBHOOK;
        foreach ($webhook as $value) {
            try {
                $hook['link'] = $value;
                $hook['type'] = 'share_chat';
                $service = NoticeService::getInstance($type, $hook);
                if (! $service instanceof NoticeInterface) {
                    return self::setError('实例化消息服务错误');
                }
                $subject = 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName();
                $data['report_name'] = $subject;
                $data['file_url'] = $this->reportListModel->getAttr('file_url');
                $res = $service->sendSingleMessage($data);
                if ($res) {
                    $msg[] = '成功';
                }
            } catch (\Exception $e) {
                $msg[] = $value;
                continue;
            }

        }
        // 发送成功记录
        $res = $this->updateStatus($msg, [], $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送企业微信.
     * @return bool
     */
    private function sendWeChat(): bool
    {
        $type = $this->getSendType();
        $receiveStaffIds = $this->getStaff();
        // 企业微信
        $service = NoticeService::getInstance($type);
        if (! $service instanceof NoticeInterface) {
            return self::setError('实例化消息服务错误');
        }
        // 推送消息接受人
        $memberId = $service->getMember($receiveStaffIds);
        $data = [
            'touser' => $memberId,
            'msgtype' => 'textcard',
            'agentid' => 1000004,
            'textcard' => [
                'title' => 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName(),
                'description' => '📅报表日期：' . $this->reportListModel->getAttr('date') . "\n🕙报表时间：" . $this->reportListModel->getAttr('hour') . ':00',
                'url' => $this->reportListModel->getAttr('file_url'),
                'btntxt' => '🔎 详情',
            ],
        ];
        $res = $service->sendMessages($data);
        // 发送成功记录
        $res = $this->updateStatus($res, $receiveStaffIds, $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送企业微信 webhook.
     * @return bool
     */
    private function sendWeChatWebHook(): bool
    {
        $webhook = $this->getWebHook();
        // 企业微信webhook
        $msg = [];
        $type = ReportRecordEnum::REPORT_RECORD_WE_CHAT_WEBHOOK;
        foreach ($webhook as $value) {
            try {
                $hook['link'] = $value;
                $service = NoticeService::getInstance($type, $hook);
                if (! $service instanceof NoticeInterface) {
                    return self::setError('实例化消息服务错误');
                }
                $sendDate = date('Y-m-d', strtotime(strval($this->reportListModel->getAttr('date'))));
                $subject = 'V3【' . ReportRecordEnum::REPORT_RECORD_DATE_TYPE[$this->getReportDateType()] . '】' . $this->getReportName();
                $data['send_date'] = $sendDate;
                $data['title'] = $subject;
                $data['messageUrl'] = $this->reportListModel->getAttr('file_url');
                $res = $service->sendSingleMessage($data);
                if ($res) {
                    $msg[] = '成功';
                }
            } catch (\Exception $e) {
                $msg[] = $value;
                continue;
            }

        }
        // 发送成功记录
        $res = $this->updateStatus($msg, [], $this->reportListModel);
        if (! $res) {
            return self::setError('发送失败');
        }
        return true;
    }

    /**
     * 发送报表回调记录.
     * @param $res
     * @param $receiveStaffIds
     * @param $model
     * @return bool
     */
    private function updateStatus($res, $receiveStaffIds, $model): bool
    {
        if ($res) {
            // 发送成功，记录日志
            $model->setAttr('success_staff_id', json_encode($receiveStaffIds));
            $model->setAttr('status', ReportRecordListModel::STATUS_SEND);
            $model->setAttr('error_msg', '发送成功');
        } else {
            // 修改发送失败的状态
            $model->setAttr('status', ReportRecordListModel::STATUS_FAIL);
            $model->setAttr('error_msg', '发送失败');
        }
        if (! $model->save()) {
            return false;
        }
        return true;
    }
}
